//
//  ReversiController.m
//  Reversi
//	
//  Created by 成瀬 龍人 on 2/4/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "ReversiController.h"
#import "ReversiBoard.h"
#include <mach/mach_time.h>

@implementation ReversiController

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)application{
	return YES;
}

- (void)applicationDidFinishLaunching:(NSNotification*)notification{
	[self openInitializeWindow:self];
}

- (IBAction)putStone:(id)sender{
	[self performSelector:putStoneInCurrentState withObject:sender];
}

- (IBAction)openInitializeWindow:(id)sender{
	[[NSApplication sharedApplication]
	 beginSheet:initializePanel modalForWindow:reversiWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
}

- (void)initReversi:(id<ReversiPlaying>)aFirstPlayer:(id<ReversiPlaying>)aSecondPlayer{
	board = [[ReversiBoard alloc] initForGame];
	[boardViewString initWithBoard:board];
	firstPlayer = (aFirstPlayer == nil) ? [[ReversiPlayer alloc] initWithField:xPositionField:yPositionField] : aFirstPlayer;
	secondPlayer = (aSecondPlayer == nil) ? [[ReversiPlayer alloc] initWithField:xPositionField:yPositionField] : aSecondPlayer;
	currentPlayer = firstPlayer;
	currentPlayerStone = REVERSI_STONE_BLACK;
	[putButton setAttributedTitle:[NSString stringWithFormat:@"Put %@", ReversiStone2String(currentPlayerStone)]];
	[xPositionField setEditable:true];
	[yPositionField setEditable:true];			
	[xPositionField selectText: self];	
	putStoneInCurrentState = @selector(_putStoneInSelectStonePositionState:);	
	NSLog(@"initialize board");
}

- (void)_putStoneInSelectStonePositionState:(id)sender{
	//次の手を選択
	ReversiBoardPosition* pos = [currentPlayer nextHand:currentPlayerStone :board];
	
	//選択した手を置けなかった場合は、何もせず状態はそのまま
	if (nil == pos || ![board isPutOK: currentPlayerStone: pos]){
		[xPositionField selectText:self];
		NSLog(@"not put!");
		NSLog(@"change to select stone state.");
		return ;
	}
	//置ける場合は、石を返してアニメーションを開始
	else {
		NSArray* line_array = [board putAndChangeEx:currentPlayerStone:pos];
		[self _changeStateFromSelectStonePositionStateWhenPutStone:pos:line_array];
		return ;
	}
}

- (void)_putStoneInAnimationState:(id)sender{
	//アニメーション中にボタンが押されても何もしない
	NSLog(@"call in animation.");
}

- (void)_putStoneInPassState:(id)sender{
	//パスする
	[self _changeStateFromPassStateWhenPass];
}

- (void)_changeStateFromSelectStonePositionStateWhenPutStone:(ReversiBoardPosition*)pos:(NSArray*)line_array{
	//返す石の座標の配列を作成
	NSMutableArray* positions = [[NSMutableArray alloc] init];
	[positions addObject:pos];
	for(ReversiBoardLineRange* line in line_array){
		for(ReversiBoardPosition* _pos in line){
			[positions addObject:_pos];
		}
	}
	//アニメーションを開始
	NSTimer* timer = [NSTimer timerWithTimeInterval:0.2
											 target:self
										   selector:@selector(_updateAnimation:)
										   userInfo:positions
											repeats:true];
	[[NSRunLoop currentRunLoop] addTimer:timer
								 forMode:NSDefaultRunLoopMode];
	//ボタンの表示文字を"In animation"に変更
	[putButton setAttributedTitle:[NSString stringWithFormat:@"In animation"]];
	//入力不可にして状態をAnimationStateに変更
	[xPositionField setEditable:false];
	[yPositionField setEditable:false];	
	putStoneInCurrentState = @selector(_putStoneInAnimationState:);	
	NSLog(@"change to animation state");	
}

- (void)_changeStateFromPassStateWhenPass{
	id<ReversiPlaying> nextPlayer = (currentPlayerStone == REVERSI_STONE_BLACK) ?  secondPlayer : firstPlayer;
	ReversiStone nextPlayerStone = (currentPlayerStone == REVERSI_STONE_BLACK) ?  REVERSI_STONE_WHITE : REVERSI_STONE_BLACK;
	//次がユーザが入力するターンなら、入力可能にする
	if ([(NSObject*)nextPlayer isKindOfClass:[ReversiPlayer class]]){
		[xPositionField setEditable:true];
		[yPositionField setEditable:true];			
		[xPositionField selectText: self];
	}
	//ユーザで無ければ入力不可にしてボタンを選択
	else {
		[xPositionField setEditable:false];
		[yPositionField setEditable:false];	
		[putButton selectCell:nil];
	}
	//ボタンの表示文字を"Put @"か"Put O"に変更
	[putButton setAttributedTitle:[NSString stringWithFormat:@"Put %@", ReversiStone2String(nextPlayerStone)]];
	//次のユーザに処理を渡し、SelectStonePositionStateに状態を変更
	currentPlayerStone = nextPlayerStone;
	currentPlayer = nextPlayer;
	putStoneInCurrentState = @selector(_putStoneInSelectStonePositionState:);
	NSLog(@"change to select stone state.");	
}

- (void)_changeStateFromAnimationStateWhenGameOver{
	//ゲームオーバー画面をシートパネルで出す
	[[NSApplication sharedApplication]
	 beginSheet:gameResultPanel modalForWindow:reversiWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
}

- (void)_changeStateFromAnimationStateWhenNoPutPosition{
	id<ReversiPlaying> nextPlayer = (currentPlayerStone == REVERSI_STONE_BLACK) ?  secondPlayer : firstPlayer;
	ReversiStone nextPlayerStone = (currentPlayerStone == REVERSI_STONE_BLACK) ?  REVERSI_STONE_WHITE : REVERSI_STONE_BLACK;
	//必ずパスするので、入力不可にする
	[xPositionField setEditable:false];
	[yPositionField setEditable:false];
	//ボタンの文字を"Pass @"か"Pass O"に変更
	[putButton setAttributedTitle:[NSString stringWithFormat:@"Pass %@", ReversiStone2String(currentPlayerStone)]];
	//putボタンをselect状態にする
	[putButton selectCell:nil];
	//つぎのプレイヤーに制御を渡し、現在の状態をputStoneStateに変更
	currentPlayerStone = nextPlayerStone;
	currentPlayer = nextPlayer;
	putStoneInCurrentState = @selector(_putStoneInPassState:);
	NSLog(@"change to pass sate");
}

- (void)_changeStateFromAnimationStateWhenEndAnimation{
	id<ReversiPlaying> nextPlayer = (currentPlayerStone == REVERSI_STONE_BLACK) ?  secondPlayer : firstPlayer;
	ReversiStone nextPlayerStone = (currentPlayerStone == REVERSI_STONE_BLACK) ?  REVERSI_STONE_WHITE : REVERSI_STONE_BLACK;
	//次のプレイヤーがユーザの場合は、座標を入力可能にし、x入力フィールドを選択状態にする
	if ([(NSObject*)nextPlayer isKindOfClass:[ReversiPlayer class]]){
		[xPositionField setEditable:true];
		[yPositionField setEditable:true];	
		[xPositionField selectText:self];
	}
	//それ以外なら、入力不可にしておく
	else{
		[xPositionField setEditable:false];
		[yPositionField setEditable:false];	
		[putButton selectCell:nil];
	}
	//ボタンの表示文字を"Put @"か"Put O"に変更
	[putButton setAttributedTitle:[NSString stringWithFormat:@"Put %@", ReversiStone2String(nextPlayerStone)]];
	//次のプレイヤーに制御を渡し、状態をSelectStonePositionに変更
	currentPlayerStone = nextPlayerStone;
	currentPlayer = nextPlayer;
	putStoneInCurrentState = @selector(_putStoneInSelectStonePositionState:);				
	NSLog(@"change to select stone state");
}

- (void)_updateAnimation:(NSTimer*)timer{
	ReversiStone nextPlayerStone = (currentPlayerStone == REVERSI_STONE_BLACK) ?  REVERSI_STONE_WHITE : REVERSI_STONE_BLACK;
	NSMutableArray* positions = [timer userInfo];
	
	//もう返す石が無かったら終了
	if([positions count] == 0){
		[timer invalidate];
		//ゲームオーバーだったらゲームオーバー画面をだす
		if ([board isGameOver]){
			[self _changeStateFromAnimationStateWhenGameOver];
			return ;
		}
		//次のプレイヤーが置く場所が無ければパス状態へ
		else if(0 == [board allocatablePositionsNum:nextPlayerStone]){
			[self _changeStateFromAnimationStateWhenNoPutPosition];
			return ;
		}
		//アニメーションを終了し、次のプレイヤーへ制御を渡す
		else {
			[self _changeStateFromAnimationStateWhenEndAnimation];
			return ;
		}
	}
	//アニメーションを更新
	else{
		//配列の先頭の場所を返す
		ReversiBoardPosition* pos = [positions objectAtIndex:0];
		[boardViewString put:currentPlayerStone
						 pos:pos];
		//次の場所が先頭に来るように先頭を削除
		[positions removeObjectAtIndex:0];		
		NSLog(@"in anime");
		return ;
	}
}

- (bool)isBlackWin{
	return [board numberOf:REVERSI_STONE_BLACK] > [board numberOf:REVERSI_STONE_WHITE];
}

- (bool)isWhiteWin{
	return [board numberOf:REVERSI_STONE_BLACK] < [board numberOf:REVERSI_STONE_WHITE];
}

- (bool)isDraw{
	return [board numberOf:REVERSI_STONE_BLACK] == [board numberOf:REVERSI_STONE_WHITE];
}

@end
